package logic

import (
	"context"
	"encoding/json"
	"strconv"

	"go-zero-admin/apps/user/rpc/internal/svc"
	"go-zero-admin/apps/user/rpc/user"
	"go-zero-admin/model"
	"go-zero-admin/pkg/config"
	"go-zero-admin/pkg/errorx"
	"go-zero-admin/pkg/utils"

	"github.com/jinzhu/copier"
	"github.com/zeromicro/go-zero/core/logx"
)

type PermmenuLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewPermmenuLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PermmenuLogic {
	return &PermmenuLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

//  权限菜单
func (l *PermmenuLogic) Permmenu(in *user.UserPermMenuReq) (*user.UserPermMenuResp, error) {

	online, err := l.svcCtx.Redis.Get(config.SysOnlineUserCachePrefix + strconv.FormatInt(in.UserId, 10))
	if err != nil || online == "" {
		return nil, errorx.NewDefaultError(errorx.AuthErrorCode)
	}

	// 查询用户信息
	userModel, err := l.svcCtx.SysUserModel.FindOne(l.ctx, in.UserId)

	if err != nil {
		return nil, errorx.NewDefaultError(errorx.ServerErrorCode)
	}
	var roles []uint64

	//用户所属角色
	err = json.Unmarshal([]byte(userModel.RoleIds), &roles)

	if err != nil {
		return nil, errorx.NewDefaultError(errorx.ServerErrorCode)
	}

	var permMenu []uint64
	var userPermMenu []*model.SysPermMenu
	userPermMenu, permMenu, err = l.countUserPermMenu(roles, permMenu)
	if err != nil {

		return nil, errorx.NewDefaultError(errorx.ServerErrorCode)
	}

	var menu user.Menu
	menuList := make([]user.Menu, 0)
	permList := make([]string, 0)
	_, err = l.svcCtx.Redis.Del(config.SysLoginCaptchaCachePrefix + strconv.FormatInt(in.UserId, 10))
	for _, v := range userPermMenu {
		err := copier.Copy(&menu, &v)
		if err != nil {
			return nil, errorx.NewDefaultError(errorx.ServerErrorCode)
		}
		if menu.Type != config.SysDefaultPermType {
			menuList = append(menuList, menu)
		}
		var perArray []string
		err = json.Unmarshal([]byte(v.Perms), &perArray)
		if err != nil {
			return nil, errorx.NewDefaultError(errorx.ServerErrorCode)
		}
		for _, p := range perArray {
			p = config.SysPermMenuPrefix + p
			_, err := l.svcCtx.Redis.Sadd(config.SysPermMenuCachePrefix+strconv.FormatInt(in.UserId, 10), p)
			if err != nil {
				return nil, errorx.NewDefaultError(errorx.ServerErrorCode)
			}
			permList = append(permList, p)
		}
	}
	var menus []*user.Menu
	err = copier.Copy(&menus, &menuList)
	if err != nil {
		return nil, err
	}
	return &user.UserPermMenuResp{
		Menus: menus,
		//Menus: menuList,
		Perms: utils.ArrayUniqueValue[string](permList),
	}, nil
}

func (l *PermmenuLogic) countUserPermMenu(roles []uint64, permMenu []uint64) ([]*model.SysPermMenu, []uint64, error) {

	if utils.ArrayContainValue(roles, config.SysSuperRoleId) {
		SysPermMenus, err := l.svcCtx.SysPermMenuModel.FindAll(l.ctx)
		if err != nil {
			return nil, permMenu, err
		}
		return SysPermMenus, permMenu, nil
	} else {
		for _, roleId := range roles {
			// 查询角色信息
			role, err := l.svcCtx.SysRoleModel.FindOne(l.ctx, roleId)
			if err != nil && err != model.ErrNotFound {
				return nil, permMenu, errorx.NewDefaultError(errorx.ServerErrorCode)
			}

			var perms []uint64
			//	角色所拥有的权限id
			err = json.Unmarshal([]byte(role.PermMenuIds), &perms)
			if err != nil {
				return nil, permMenu, errorx.NewDefaultError(errorx.ServerErrorCode)
			}
			if role.Status != 0 {
				permMenu = append(permMenu, perms...)
			}
			//	汇总用户所属角色权限id
			permMenu = l.getRolePermMenu(permMenu, roleId)
		}

		//	过渡重复的权限id
		permMenu = utils.ArrayUniqueValue[uint64](permMenu)
		var roleIds string
		for i, id := range permMenu {
			if i == 0 {
				roleIds = strconv.FormatUint(id, 10)
			}
			roleIds = roleIds + "," + strconv.FormatUint(id, 10)
		}

		if len(roleIds) == 0 {
			return nil, permMenu, nil
		}

		//	根据权限id获取具体权限
		sysPermMenus, err := l.svcCtx.SysPermMenuModel.FindByIds(l.ctx, roleIds)
		if err != nil {
			return nil, permMenu, err
		}
		return sysPermMenus, permMenu, nil
	}
}
func (l *PermmenuLogic) getRolePermMenu(perms []uint64, roleId uint64) []uint64 {
	roles, err := l.svcCtx.SysRoleModel.FindSubRole(l.ctx, roleId)
	if err != nil && err != model.ErrNotFound {
		return perms
	}
	for _, role := range roles {
		var subPerms []uint64
		err = json.Unmarshal([]byte(role.PermMenuIds), &subPerms)
		perms = append(perms, subPerms...)
		perms = l.getRolePermMenu(perms, role.Id)
	}
	return perms
}
